package logger

import (
    "io"
    "net/http"
    "os"
    "path/filepath"
    "time"

    "github.com/gorilla/websocket"
    "github.com/lestrrat-go/file-rotatelogs"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "libgo/utils"
    "libgo/utils/LineCacheWriter"
    "libgo/utils/MsgBus"
)


const (
    TOPIC_SYS_LOG = "/debug/log"
)

type Logger struct {
    mb  *MsgBus.MessageBus
    lcw *LineCacheWriter.LineCacheWriter
    ws  *websocket.Upgrader
}

func New() *Logger {
    x := &Logger{}
    x.mb = MsgBus.New()
    x.ws = &websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool { return true },
    }
    x.lcw = LineCacheWriter.New(512).OnMessage(func(i int64, bytes []byte) {

        x.mb.Pub(TOPIC_SYS_LOG, bytes)
    })
    return x
}


func (s *Logger) NewZapLogger(AppName string) *zap.Logger {

    Level := zap.NewAtomicLevel()
    Level.SetLevel(zap.DebugLevel)

    encoderCfg := zap.NewProductionEncoderConfig()
    encoderCfg.LevelKey = "lv"
    encoderCfg.CallerKey = "src"
    encoderCfg.TimeKey = "ts"
    encoderCfg.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05.000")


    rotator, err := rotatelogs.New(
        filepath.Join(utils.ProjectRoot(), "/log/"+AppName+"-%Y-%m-%d.log"),

        rotatelogs.WithMaxAge(time.Hour*24*30),
        rotatelogs.WithRotationTime(time.Hour*24*7),
        rotatelogs.WithRotationSize(1024*1024*10),
    )
    if err != nil {
        panic(err)
    }

    core := zapcore.NewCore(
        zapcore.NewJSONEncoder(encoderCfg),
        zapcore.AddSync(io.MultiWriter(
            os.Stdout,
            rotator,
            s.lcw,
        )),
        Level,
    )
    return zap.New(core)













}

func (s *Logger) ws_handler(w http.ResponseWriter, r *http.Request) {
    ws, err := s.ws.Upgrade(w, r, nil)
    if err != nil {

        return
    }
    defer func() {
        _ = ws.Close()
    }()























    pipe := s.mb.Sub(TOPIC_SYS_LOG)
    for {

        msg, err := pipe.Poll(0)
        if err != nil {
            continue
        }
        _ = ws.SetWriteDeadline(time.Now().Add(time.Second * 3))
        if err = ws.WriteMessage(websocket.TextMessage, msg); err != nil {
            continue
        }
    }
}

func (s *Logger) NewWebSocketLoggerHandler() func(w http.ResponseWriter, r *http.Request) {
    return s.ws_handler
}


func (s *Logger) BStartWebsocketServer(addr string) {
    http.HandleFunc("/ws/debug/log", s.ws_handler)
    _ = http.ListenAndServe(addr, nil)
}
